﻿using Microsoft.Azure.ActiveDirectory.GraphClient;
using Microsoft.Azure.ActiveDirectory.GraphClient.Extensions;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Security.Principal;
using System.Threading.Tasks;
using System.Web;

namespace CloudStorageLight.Core
{
    public static class AzureAdUtil
    {


        public static IPrincipal CreatePrincipal(string authority, string clientId, string appKey, string tenantId, string userName)
        {
            var client = CreateActiveDirectoryClient(authority, clientId, appKey, tenantId);
            var u = GetUser(client, userName);
            var r = ListGroupOfMember(client, u).Select(x=>x.ToLower()).ToArray();
            return new GenericPrincipal(new GenericIdentity(userName), r);
        }

        private static ActiveDirectoryClient CreateActiveDirectoryClient(string authority, string clientId, string appKey, string tenantId)
        {
            if (!activeDirectoryClient.ContainsKey(authority + tenantId) || renewTime[authority + tenantId] < DateTime.UtcNow)
            {
                var reso = "https://graph.windows.net";

                var authContext = new Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext(authority);
                var clientCredential = new Microsoft.IdentityModel.Clients.ActiveDirectory.ClientCredential(clientId, appKey);

                var result = authContext.AcquireToken(reso, clientCredential);

                var baseServiceUri = new Uri(reso);
#pragma warning disable 1998
                Func<Task<string>> callback = async () =>
                {
                    if (string.IsNullOrEmpty(result.AccessToken))
                    {
                        throw new Exception("Authorization Required.");
                    }
                    return result.AccessToken;
                };
#pragma warning restore 1998
                activeDirectoryClient[authority + tenantId] =
                    new ActiveDirectoryClient(new Uri(baseServiceUri, tenantId), callback);
                renewTime[authority + tenantId] = DateTime.UtcNow.AddMinutes(10);

            }
            return activeDirectoryClient[authority + tenantId];
        }




        static Dictionary<string,ActiveDirectoryClient> activeDirectoryClient = new Dictionary<string,ActiveDirectoryClient>();
        static Dictionary<string,DateTime> renewTime = new Dictionary<string,DateTime>();


        public static List<Microsoft.Azure.ActiveDirectory.GraphClient.Group> ListGroup(string authority, string clientId, string appKey, string tenantId)
        {
            var client = CreateActiveDirectoryClient(authority, clientId, appKey, tenantId);

            var list = new List<string>();
            var groupList = new List<Microsoft.Azure.ActiveDirectory.GraphClient.Group>();

            IPagedCollection<IGroup> pagedCollection = client.Groups.ExecuteAsync().Result;
            do
            {
                List<IGroup> groups = pagedCollection.CurrentPage.ToList();
                foreach (IGroup group in groups)
                {
                    groupList.Add((Microsoft.Azure.ActiveDirectory.GraphClient.Group)group);
                }
                pagedCollection = pagedCollection.GetNextPageAsync().Result;
            } while (pagedCollection != null && pagedCollection.MorePagesAvailable);

            Debug.WriteLine(string.Join(",", groupList));

            return groupList;
        }

        public static List<Microsoft.Azure.ActiveDirectory.GraphClient.User> ListUser(string authority, string clientId, string appKey, string tenantId)
        {
            var client = CreateActiveDirectoryClient(authority, clientId, appKey, tenantId);

            var list = new List<string>();
            var userList = new List<Microsoft.Azure.ActiveDirectory.GraphClient.User>();

            IPagedCollection<IUser> pagedCollection = client.Users.ExecuteAsync().Result;
            do
            {
                List<IUser> users = pagedCollection.CurrentPage.ToList();
                foreach (IUser user in users)
                {
                    userList.Add((Microsoft.Azure.ActiveDirectory.GraphClient.User)user);
                }
                pagedCollection = pagedCollection.GetNextPageAsync().Result;
            } while (pagedCollection != null && pagedCollection.MorePagesAvailable);

            return userList;
        }


        public static User GetUser(ActiveDirectoryClient activeDirectoryClient, string username)
        {
            var list = new List<string>();
            var usersList = new List<Microsoft.Azure.ActiveDirectory.GraphClient.User>();

            IPagedCollection<IUser> pagedCollection = activeDirectoryClient.Users.Where(x => x.UserPrincipalName == username).ExecuteAsync().Result;
            User user = (User)pagedCollection.CurrentPage.FirstOrDefault();
            return user;
        }

        private static IEnumerable<string> ListGroupOfMember(ActiveDirectoryClient activeDirectoryClient, User user)
        {
            IUserFetcher retrievedUserFetcher = (User)user;
            IPagedCollection<IDirectoryObject> pagedCollection = retrievedUserFetcher.MemberOf.ExecuteAsync().Result;
            do
            {
                List<IDirectoryObject> directoryObjects = pagedCollection.CurrentPage.ToList();
                foreach (IDirectoryObject directoryObject in directoryObjects)
                {
                    if (directoryObject is Group)
                    {
                        Group group = directoryObject as Group;
                        yield return group.DisplayName;
                    }
                }
                pagedCollection = pagedCollection.GetNextPageAsync().Result;
            } while (pagedCollection != null && pagedCollection.MorePagesAvailable);
        }

        public static IEnumerable<string> ListGroupOfMember(string authority, string clientId, string appKey, string tenantId, string user)
        {
            var client = CreateActiveDirectoryClient(authority, clientId, appKey, tenantId);
            var u = GetUser(client, user);
            return ListGroupOfMember(client, u);

        }
    }

}
